package com.nwpu.vote.control;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.jdo.JDOObjectNotFoundException;
import javax.jdo.PersistenceManager;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;

import com.nwpu.vote.model.*;
import com.nwpu.vote.util.*;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

public class VoteQuerierImpl implements VoteQuerier {

	public static VoteQuerier instance = new VoteQuerierImpl();
	private static Logger logger = Logger.getLogger(VoteQuerierImpl.class.getName());
	
	private VoteQuerierImpl() {}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<Vote> listRecentVotes(int count) throws PersistentException {
			PersistenceManager pm = PMF.get().getPersistenceManager();
			
			javax.jdo.Query query = pm.newQuery(Vote.class);
			query.setOrdering("createDate desc");
			query.setRange(0,count-1);
			
	        List<Vote> recentVotes = (List<Vote>) query.execute();
	        
	        logger.log(Level.FINE, "list recent votes, count :"+recentVotes.size());
	        return recentVotes;
	}
	
	@Override
	public List<VoteUser> listActiveUsers(int count) {
		if(count <= 0) return new ArrayList<VoteUser>();
			
		List<VoteUser> activeUsers = new ArrayList<VoteUser>();
		try {
			List<Vote> recentVotes = listRecentVotes(count);
			for(Vote vote : recentVotes){
				List<VoteUser> users = vote.getVotedUsers();
				for(VoteUser user : users){
					if(!activeUsers.contains(user)){//TODO: can be detected?
						activeUsers.add(user);
						if(activeUsers.size() >= count)
							return activeUsers;
					}
				}
			}
			
		} catch (PersistentException e) {
			logger.log(Level.WARNING,e.getMessage(),e);
		}
		logger.log(Level.INFO,"Not enough user count, count = "+activeUsers.size()+" < "+count);
		return activeUsers;
	}
	
	@Override
	public List<String> listPopularTags(int count){
    /*		List<String> popularTags = new ArrayList<String>();
		
		try {
			List<Vote> recentVotes = VotePersistentImpl.instance.listRecentVotes(count);
			for(Vote vote: recentVotes){
				String tags = vote.displayTags();
				String[] tagArray = tags.split(" ");
				for(String tagname:tagArray){
					if(!popularTags.contains(tagname)){
						popularTags.add(tagname);
					}
				}
			}
			
		} catch (PersistentException e) {
			logger.log(Level.WARNING,e.getMessage(),e);
		}

		return popularTags;*/
		
		List<String> popularTags = new ArrayList<String>();
		
		try {
			List<Vote> recentVotes = listRecentVotes(count);
			for(Vote vote: recentVotes){
				String tags = vote.displayTags();
				String[] tagArray = tags.split(" ");
				for(String tagname:tagArray){
					if(!popularTags.contains(tagname)){
						popularTags.add(tagname);
					}
				}
			}
			
		} catch (PersistentException e) {
			logger.log(Level.WARNING,e.getMessage(),e);
		}

		return popularTags;
	}

	/**
	 * @param createDateOrder
	 */
    @SuppressWarnings("unchecked")
    public List<Vote> getAllVotes(QUERY_ORDER createDateOrder){
		PersistenceManager pm = PMF.get().getPersistenceManager();
		
		javax.jdo.Query query = pm.newQuery(Vote.class);
		if(createDateOrder == QUERY_ORDER.ASC)
			query.setOrdering("createDate asc");
		else if(createDateOrder == QUERY_ORDER.DESC)
			query.setOrdering("createDate desc");
		
		List<Vote> votes = (List<Vote>) query.execute();
        
        logger.log(Level.FINE, "list all votes, count :"+votes.size());
        return votes;
	}
    
	@SuppressWarnings("unchecked")
	/**
	 * @param nameOrder
	 */
    public List<VoteUser> getAllVoteUsers(QUERY_ORDER nameOrder){
		PersistenceManager pm = PMF.get().getPersistenceManager();
		
		javax.jdo.Query query = pm.newQuery(VoteUser.class);
		if(nameOrder == QUERY_ORDER.ASC)
			query.setOrdering("name asc");
		else if(nameOrder == QUERY_ORDER.DESC)
			query.setOrdering("name desc");
		
		List<VoteUser> users = (List<VoteUser>) query.execute();
        
        logger.log(Level.FINE, "list all vote users, count :"+users.size());
        return users;
	}
    
	/**
	 * @param nameOrder
	 */
    @SuppressWarnings("unchecked")
	public List<Tag> getAllTags(QUERY_ORDER nameOrder){
		PersistenceManager pm = PMF.get().getPersistenceManager();
		
		javax.jdo.Query query = pm.newQuery(Tag.class);
		if(nameOrder == QUERY_ORDER.ASC)
			query.setOrdering("createDate asc");
		else if(nameOrder == QUERY_ORDER.DESC)
			query.setOrdering("createDate desc");
		
		List<Tag> tags = (List<Tag>) query.execute();
        
        logger.log(Level.FINE, "list all tags, count :"+tags.size());
        return tags;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Vote> listOpeningVotes() throws PersistentException {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		
		Date now = new Date();
		javax.jdo.Query query = pm.newQuery(Vote.class);
		query.declareImports("import java.util.Date");
		query.declareParameters("Date now");
		//query.setFilter("startDate < now && finishDate > now");
		//java.lang.IllegalArgumentException: 
		//    Only one inequality filter per query is supported.  Encountered both startDate and finishDate
		query.setFilter("finishDate > now");
		query.setOrdering("finishDate desc");
		
        List<Vote> openingVotes = (List<Vote>) query.execute(now);
        
        logger.log(Level.FINE, "list opening votes, count :"+openingVotes.size());
        return openingVotes;
	}

    /*
	@Override
	public List<Vote> searchVote(String keywords, int start, int count) throws PersistentException {
		
		List<Vote> result = new ArrayList<Vote>();
		
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Key generatedKey = KeyFactory.createKey(EFileIndex.class.getSimpleName(), Constant.KEY);
		
		EFileIndex fileIndex = null;
		try{
			fileIndex = pm.getObjectById(EFileIndex.class,KeyFactory.keyToString(generatedKey));
			
			Analyzer analyzer = new StandardAnalyzer();
			// Now search the index:
		    IndexSearcher isearcher = new IndexSearcher(fileIndex.getDirectory());
		    Query query = MultiFieldQueryParser.parse(new String[] { keywords,
					keywords, keywords, keywords, keywords },
					new String[] { "filename", "description", "tags",
							"username", "useremail" }, analyzer);
		    
		    Hits hits = isearcher.search(query);
		    // Iterate through the results:
		    for (int i = start-1, j=0; i < hits.length()&&j<count; i++,j++) {
		      Document hitDoc = hits.doc(i);
		      String id = hitDoc.get("id");
		      
		      //retrive the efile object from Google data store
		      try{
		    	  Vote vote = pm.getObjectById(Vote.class,id);
		    	  result.add(vote);
		      }catch(JDOObjectNotFoundException e){
		    	  logger.log(Level.WARNING,e.getMessage(),e);
		      }
		    }
		    isearcher.close();
		    fileIndex.getDirectory().close();
			
		}catch(JDOObjectNotFoundException e){	//first time , index doesn't exist ...
			//fileIndex = new EFileIndex();
			logger.log(Level.WARNING,"[lucene index file doesn't exist]"+e.getMessage(),e);
		} catch (CorruptIndexException e) {
			logger.log(Level.WARNING,e.getMessage(),e);
		} catch (IOException e) {
			logger.log(Level.WARNING,e.getMessage(),e);
		} catch (ParseException e) {
			logger.log(Level.WARNING,e.getMessage(),e);
		}
		
		return result;
	}
	*/
    
}
